package com.ruifu.bom.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruifu.bom.dto.MaterielImportDTO;
import com.ruifu.bom.mapper.MaterielMapper;
import com.ruifu.bom.mapper.MaterielStructureMapper;
import com.ruifu.bom.mapper.MaterielVersionsMapper;
import com.ruifu.bom.service.MaterielStructureService;
import com.ruifu.bom.vo.MaterielAndVersionsVO;
import com.ruifu.bom.vo.MaterielBom;
import com.ruifu.bom.vo.MaterielBomCondition;
import com.ruifu.common.po.Materiel;
import com.ruifu.common.po.MaterielStructure;
import com.ruifu.common.po.MaterielVersions;
import com.ruifu.common.utils.BeanConverter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 结构表业务逻辑层实现类
 *
 * @author gqx
 */
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class MaterielStructureServiceImpl extends ServiceImpl<MaterielStructureMapper, MaterielStructure> implements MaterielStructureService {
    @Autowired(required = false)
    private MaterielStructureMapper structureMapper;

    @Autowired(required = false)
    private MaterielVersionsMapper materielVersionsMapper;

    @Autowired(required = false)
    private MaterielMapper materielMapper;

    @Override
    public void saveImport(List<MaterielImportDTO> materielImportDTOList) {
        List<MaterielStructure> structureList = BeanConverter.copyList(materielImportDTOList, MaterielStructure.class);
        for (MaterielStructure structure : structureList) {
            structureMapper.insert(structure);
        }
    }


    /**
     * bom子物料信息查看
     *
     * @param pMvId 选中节点物料版本id
     * @param mvIds 子节点物料版本id集合
     * @return
     */
    @Override
    public List<MaterielAndVersionsVO> findByIds(Long pMvId, List<Long> mvIds) {
        List<MaterielAndVersionsVO> materielBomList = new ArrayList<>();

        for (Long mvId : mvIds) {

            //通过物料对象和查询条件获取物料版本
            MaterielVersions materielVersions = this.materielVersionsMapper.findByMvId(mvId.toString());

            if (null != materielVersions) {
                MaterielAndVersionsVO materielBom = new MaterielAndVersionsVO();
                BeanConverter.copyProperties(materielVersions, materielBom);
                materielBomList.add(materielBom);
            }
        }

        return materielBomList;
    }


    /**
     * 根据父物料id向下逐级查询子节点（使用递归完成）
     *
     * @param mId
     * @param condition
     * @param bomList
     */
    @Override
    public void findMaterielByPid(Long mId, MaterielBomCondition condition, List<MaterielBom> bomList) {

        //查询当前id的物料对象
        Materiel materiel = materielMapper.selectById(mId);

        if (null == materiel) {
            //未查询到该id下面的物料信息
        } else {
            MaterielVersions mVersion = this.getMaterielVersionsByCondition(materiel, condition);

            //如果当前物料找到对应节点信息
            if (null != mVersion) {
                Long mVersionId = mVersion.getMvId();   //父节点的指定版本id

                //1.先插入父节点信息
                if (CollectionUtil.isEmpty(bomList)) {
                    MaterielBom mBomParent = new MaterielBom();
                    mBomParent.setMaterielName(materiel.getMlName());
                    mBomParent.setMaterielClass(materiel.getMlClass());
                    mBomParent.setMaterielObject(materiel.getIfMaterialObject());
                    mBomParent.setMaterielCode(materiel.getMlCode());

                    mBomParent.setMaterielMlId(mId);
                    mBomParent.setMaterielMvId(mVersionId);
                    mBomParent.setMaterielPId(0L);
                    mBomParent.setMaterielPvId(0L);
                    mBomParent.setBomType(condition.getBomType());

                    mBomParent.setMaterielIdentify(mVersion.getMvIdentify());
                    mBomParent.setMaterielDesignStatus(mVersion.getMvDesignStatus());

                    bomList.add(mBomParent);
                }

                //根据父项版本id查询结构，这个结构只会挂在当前这个版本节点之下
                List<MaterielStructure> mStructuresList =
                        structureMapper.selectList((Wrappers.<MaterielStructure>lambdaQuery()
                                .eq(MaterielStructure::getStParentProjectVersionsId, mVersionId)
                                .eq(MaterielStructure::getStBomType, condition.getBomType())));

                if (CollectionUtil.isEmpty(mStructuresList)) {
                    //1.如果根据父节点版本id查询不到数据。则证明该父节点是叶子结点。退出递归循环
                    return;
                } else {
                    //2.遍历结构表，获取当前节点子节点的操作信息
                    for (MaterielStructure mStructure : mStructuresList) {
                        MaterielBom materielBom = new MaterielBom();

                        //从结构表中获取物料id得到物料对象
                        Materiel materielChild = materielMapper.selectById(mStructure.getStMaterielId());

                        if (null != materielChild) {
                            //通过物料对象获取符合条件的物料版本
                            MaterielVersions newMaterielVersions = this.getMaterielVersionsByCondition(materielChild, condition);

                            if (null != newMaterielVersions) {
                                //父节点物料id和物料版本id
                                materielBom.setMaterielPId(mId);
                                materielBom.setMaterielPvId(mVersionId);

                                //装配数量
                                materielBom.setMaterielNum(mStructure.getStAmount());
                                //序号
                                materielBom.setMaterielSerialNumber(mStructure.getStSerialNumber());
                                materielBom.setBomType(mStructure.getStBomType());

                                //物料名称
                                materielBom.setMaterielName(materielChild.getMlName());
                                //物料代号
                                materielBom.setMaterielCode(materielChild.getMlCode());
                                //子节点物料id
                                materielBom.setMaterielMlId(materielChild.getMlId());
                                //物料类别
                                materielBom.setMaterielClass(materielChild.getMlClass());
                                //是否是模型
                                materielBom.setMaterielObject(materielChild.getIfMaterialObject());

                                //物料版本号
                                materielBom.setMaterielIdentify(newMaterielVersions.getMvIdentify());
                                //物料设计状态
                                materielBom.setMaterielDesignStatus(newMaterielVersions.getMvDesignStatus());
                                //子节点物料版本id
                                materielBom.setMaterielMvId(newMaterielVersions.getMvId());

                                bomList.add(materielBom);
                                findMaterielByPid(materielChild.getMlId(), condition, bomList);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 移除零部件
     * 删除逻辑：只删除当前这个版本节点之下的，数据库中关联的，所有下级子节点信息就可以了。剩下的不要动
     *
     * @param mlId
     * @return
     */
    @Override
    public R removeParts(Long pMvId, Long mlId) {
        try {
            //查询传入节点同父节点关联的structure信息
            MaterielStructure structure = structureMapper.selectOne((Wrappers.<MaterielStructure>lambdaQuery()
                    .eq(MaterielStructure::getStMaterielId, mlId))
                    .eq(MaterielStructure::getStParentProjectVersionsId, pMvId));

            if (null != structure) {
                //如果查出了这条数据，则将当前该关联关系删除掉（逻辑）
                structureMapper.deleteById(structure.getStId());
            }

            //this.recursionDeleteStructure(structure);
            return R.ok("移除成功！");
        } catch (Exception e) {
            log.error("移除零部件失败。异常信息：", e);
            return R.failed("移除失败");
        }


    }

    /**
     * 根据物料id，批量添加下级件关联（需要确保传过来的数据的合法性）
     *
     * @param mlIds 物料id List
     * @param pMvId 父节点版本id
     * @return
     */
    @Override
    public R addBomStructureBatch(List<Long> mlIds, Long pMvId, String bomType) {
        try {
            if (StringUtils.isEmpty(bomType)) {
                bomType = "D";
            }

            if (CollectionUtil.isNotEmpty(mlIds)) {
                //去重操作
                mlIds = mlIds.stream().distinct().collect(Collectors.toList());

                List<MaterielStructure> structures = new ArrayList<>();

                //计算挂在该版本节点之下的节点数量，用于给SerialNumber赋值
                int count = this.count(Wrappers.<MaterielStructure>lambdaQuery()
                        .eq(MaterielStructure::getStParentProjectVersionsId, pMvId));

                //用来存储判断传过来的id是否存在
                int amount;

                //判断传递过来的父物料版本是否真实存在
                MaterielVersions pVersion = this.materielVersionsMapper.selectById(pMvId);

                if (null != pVersion) {
                    for (Long mlId : mlIds) {
                        //先进行当前id过滤，判断该物料关系是否已经在结构表中存在
                        // mVersion = this.materielVersionsMapper.selectById(mlId);
                        amount = this.count(Wrappers.<MaterielStructure>lambdaQuery()
                                .eq(MaterielStructure::getStParentProjectVersionsId, pMvId)
                                .eq(MaterielStructure::getStMaterielId, mlId));

                        //只有当前节点没有曾经插入该值的时候才进行后续操作
                        if (amount == 0) {
                            count++;

                            MaterielStructure structure = new MaterielStructure();

                            //父物料版本id
                            structure.setStParentProjectVersionsId(pMvId);
                            //子物料id
                            structure.setStMaterielId(mlId);
                            //BOM类型
                            structure.setStBomType(bomType);
                            //structure.setStIsOptional(true);
                            structure.setStSerialNumber(count);

                            structures.add(structure);
                        }
                    }
                }

                //批量插入，该方法自带事务处理
                this.saveBatch(structures);
            }
            return R.ok("添加下级件成功！");

        } catch (Exception e) {
            log.error("添加下级件失败。异常信息：", e);
            return R.failed("添加下级件失败");
        }
    }

    /**
     * 根据物料实体，添加下级件
     *
     * @param cMlId 要插入的子物料id
     * @param mvId  父节点版本id
     * @return
     */
    @Override
    public R addBomStructure(Long cMlId, Long mvId, String bomType) {

        //计算挂在该版本节点之下的节点数量
        int count = this.count(Wrappers.<MaterielStructure>lambdaQuery()
                .eq(MaterielStructure::getStParentProjectVersionsId, mvId));

        MaterielStructure structure = new MaterielStructure();

        structure.setStSerialNumber(count + 1);
        structure.setStParentProjectVersionsId(mvId);
        structure.setStMaterielId(cMlId);
        //structure.setStIsOptional(true);
        structure.setStBomType(bomType);

        if (this.save(structure)) {
            return R.ok("新增成功");
        } else {
            return R.failed("新增失败");
        }

    }

    /**
     * 用于何处
     *
     * @param stMaterielId
     * @return
     */
    @Override
    public R useWhere(Long stMaterielId) {
        List<MaterielStructure> materielStructureList = new ArrayList<>();
        //得到当前选中节点
        MaterielStructure materielStructure = structureMapper.selectById((Wrappers.<MaterielStructure>lambdaQuery()
                .eq(MaterielStructure::getStMaterielId, stMaterielId)));
        List<MaterielStructure> materielStructures = this.recursionSelectStructure(materielStructureList, materielStructure);
        return R.ok(materielStructures);
    }

    private List<MaterielStructure> recursionSelectStructure(List<MaterielStructure> materielStructureList, MaterielStructure materielStructure) {
        materielStructureList.add(materielStructure);
        //根据当前节点的父id查询父对象
        MaterielStructure parentMateriel = structureMapper.selectById((Wrappers.<MaterielStructure>lambdaQuery()
                .eq(MaterielStructure::getStParentProjectVersionsId,
                        materielStructure.getStParentProjectVersionsId())));
        if (parentMateriel != null) {
            return this.recursionSelectStructure(materielStructureList, parentMateriel);
        }
        throw new RuntimeException("父版本对象为空！");
    }


    /**
     * 递归删除结构
     *
     * @param materielStructure
     */
//    private void recursionDeleteStructure(MaterielStructure materielStructure) {
//        if (materielStructure != null) {
//            structureMapper.deleteById(materielStructure);
//            //根据物料id得到根节点物料对象
//            Materiel materiel = materielMapper.selectById(materielStructure.getStMaterielId());
//
//            //得到根节点最新物料版本对象
//            //TODO 删除逻辑：只删除当前这个版本节点之下的，数据库中关联的，所有与子节点信息就可以了。剩下的不要动他
//            MaterielVersions newMaterielVersions = materielVersionsMapper.selectById(materiel.getMlNewVersionId());
//            //父项版本id等于根节点的版本id的子节点集合
//            List<MaterielStructure> materielStructures = structureMapper.selectList((Wrappers.<MaterielStructure>lambdaQuery()
//                    .eq(MaterielStructure::getStParentProjectVersionsId
//                            , newMaterielVersions.getMvId())));
//            //递归删除
//            if (CollectionUtil.isNotEmpty(materielStructures)) {
//                for (MaterielStructure structure : materielStructures) {
//                    this.recursionDeleteStructure(structure);
//                }
//            }
//        }
//    }

    /**
     * 根据物料信息，和查询条件，获取对应的物料版本
     *
     * @param materiel
     * @param condition
     * @return
     */
    private MaterielVersions getMaterielVersionsByCondition(Materiel materiel, MaterielBomCondition condition) {

        MaterielVersions mVersion = null;

        //TODO mv_plant_valid-场地有效性暂时不处理

        //判断是否需要过滤时间(起始时间,截止时间非空则进行时间过滤)
        boolean isTimeRange = StringUtils.isNotEmpty(condition.getTimeBegin());

        if (null != materiel) {
            if (isTimeRange) {
                // 勾选时间有效性，则根据时间选择来查看这个时间段之前对应的BomState
                Date beginTime = DateUtil.parseDate(condition.getTimeBegin());
                List<MaterielVersions> mVersionList = null;

                if (condition.getBomState() == 1) {
                    //1.表示查看最新版本状态，包含未发布。
                    mVersionList = materielVersionsMapper.selectList(Wrappers.<MaterielVersions>lambdaQuery()
                            .eq(MaterielVersions::getMvMaterielId, materiel.getMlId())
                            .le(MaterielVersions::getCreDate, beginTime)
                            .orderByDesc(MaterielVersions::getCreDate));

                } else if (condition.getBomState() == 0) {
                    // 2.表示查看最新发布的版本。
                    mVersionList = materielVersionsMapper.selectList(Wrappers.<MaterielVersions>lambdaQuery()
                            .eq(MaterielVersions::getMvMaterielId, materiel.getMlId())
                            .le(MaterielVersions::getMvIssueTime, beginTime)
                            .orderByDesc(MaterielVersions::getMvIssueTime));
                }
                if (CollectionUtil.isNotEmpty(mVersionList)) {
                    mVersion = mVersionList.get(0);
                }

                if (null == mVersion) {
                    //如果指定日期查不出来，则直接取最新版本
                    mVersion = materielVersionsMapper.selectById(materiel.getMlNewVersionId());
                }
            } else {
                // 未勾选时间有效性，则直接根据BomState判断。
                if (condition.getBomState() == 1) {
                    // 1.表示查看最新版本状态，包含未发布。直接根据物料的ml_new_version_id字段查询物料版本
                    mVersion = materielVersionsMapper.selectById(materiel.getMlNewVersionId());

                } else if (condition.getBomState() == 0) {
                    // 2.表示查看最新发布的版本。直接根据物料的ml_new_issue_version_id字段查询物料版本
                    mVersion = materielVersionsMapper.selectById(materiel.getMlNewIssueVersionId());
                }
            }
        }

        return mVersion;
    }
}




